package net.tarine.gastronomi.client;

import java.util.ArrayList;
import java.util.List;

import net.tarine.gastronomi.client.services.GasService;
import net.tarine.gastronomi.client.services.GasServiceAsync;
import net.tarine.gastronomi.shared.ValidationException;
import net.tarine.gastronomi.shared.to.GasUserTo;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.VerticalPanel;

public class AuthSingleton {

	private GasServiceAsync gasUserService = GWT.create(GasService.class);
	
	private static AuthSingleton instance = null;

	private List<IAuthenticatedWidget> lockedWidgets = new ArrayList<IAuthenticatedWidget>();
	
	private GasUserTo user = null;
	private boolean authorized = false;
	
	private Anchor loginAnchor = null;
	private Anchor logoutAnchor = null;
	
	private AuthSingleton() {
		loginAnchor = new Anchor("Login");
		logoutAnchor = new Anchor("Logout");
		loadUser();
	}
	
	public static AuthSingleton get() {
		if (instance == null) {
			instance = new AuthSingleton();
		}
		return instance;
	}

	public synchronized void authorizeWidget(IAuthenticatedWidget widget) {
		if (user != null) {
			if (authorized) {
				widget.unlockWidget(user);
			} else {
				lockedWidgets.add(widget);
				if (lockedWidgets.size() == 1) {
					loadUser();
				}
			}
		} else {
			lockedWidgets.add(widget);
			if (lockedWidgets.size() == 1) {
				loadUser();
			}
		}
	}
	
	private synchronized void unlockWidgets() {
		for (IAuthenticatedWidget widget:lockedWidgets) {
			widget.unlockWidget(user);
		}
		lockedWidgets.clear();
	}
	
	public Anchor getLogoutAnchor() {
		return logoutAnchor;
	}
	
	public Anchor getLoginAnchor() {
		return loginAnchor;
	}
	
	
	
	//Async methods
	
	
	private void loadUser() {
		AsyncCallback<GasUserTo> callback = new AsyncCallback<GasUserTo>() {
			@Override
			public void onFailure(Throwable caught) {
				user = null;
				authorized = false;
				loadLoginUrl();
				loadLogoutUrl();
				if (caught instanceof ValidationException) {
					new LoginPopUp(caught.getMessage(), LoginPopUp.NOT_AUTHORIZED, loginAnchor, logoutAnchor);
				} else {
					new LoginPopUp(caught.getMessage(), LoginPopUp.NOT_LOGGED, loginAnchor, logoutAnchor);
				}
				WaitSingleton.get().stop();
			}
			@Override
			public void onSuccess(GasUserTo result) {
				user = result;
				authorized = true;
				loadLoginUrl();
				loadLogoutUrl();
				unlockWidgets();
				WaitSingleton.get().stop();
			}
		};
		WaitSingleton.get().start();
		gasUserService.findGasUserFromSession(callback);
	}
	
	private void loadLoginUrl() {
		AsyncCallback<String> callback = new AsyncCallback<String>() {
			@Override
			public void onFailure(Throwable caught) {
				UiSingleton.get().addError(caught);
			}
			@Override
			public void onSuccess(String result) {
				loginAnchor.setHref(result);
			}
		};
		String destinationUrl = Window.Location.createUrlBuilder().buildString();
		gasUserService.createLoginUrl(destinationUrl, callback);
	}
	
	private void loadLogoutUrl() {
		AsyncCallback<String> callback = new AsyncCallback<String>() {
			@Override
			public void onFailure(Throwable caught) {
				UiSingleton.get().addError(caught);
			}
			@Override
			public void onSuccess(String result) {
				logoutAnchor.setHref(result);
			}
		};
		String destinationUrl = Window.Location.createUrlBuilder().buildString();
		gasUserService.createLogoutUrl(destinationUrl, callback);
	}
	
	
	//Inner classes

	
	
	private class LoginPopUp extends PopupPanel {
		
		public static final int NOT_LOGGED = 0;
		public static final int NOT_AUTHORIZED = 1;
		
		private String msg = "";
		private int popUpType;
		private Anchor loginAnchor = null;
		private Anchor logoutAnchor = null;
		
		//public LoginPopUp(int popUpType, Anchor loginAnchor, Anchor logoutAnchor) {
		//	this("", popUpType, loginAnchor, logoutAnchor);
		//}
		
		public LoginPopUp(String msg, int popUpType, Anchor loginAnchor, Anchor logoutAnchor) {
			super(false);
			this.msg=msg;
			this.popUpType = popUpType;
			this.loginAnchor = loginAnchor;
			this.logoutAnchor = logoutAnchor;
			init();
		}
		
		private void init() {
			//UI
			this.setModal(true);
			this.setGlassEnabled(true);
			//Popup
			VerticalPanel content = new VerticalPanel();
			Image bannerImg = new Image("img/banner-login.png");
			content.add(bannerImg);
			HTML title = new HTML("<h3>Il punto di incontro online per il GAS</h3>");
			content.add(title);
			HTML message = new HTML(msg);
			message.setStyleName("message-error");
			content.add(message);
			content.add(new HTML("<br/>"));
			String intro = "";
			if (popUpType == NOT_LOGGED) {
				intro = "Non hai effettuato l'accesso, per entrare nel<br/> " +
						"sito devi inserire i tuoi dati sulla pagina<br/> " +
						"di autenticazione:";
				content.add(new HTML(intro));
				content.add(loginAnchor);
			}
			if (popUpType == NOT_AUTHORIZED) {
				intro = "Hai effettuato correttamente l'accesso, ma<br/> " +
						"l'utente non è stato abilitato all'uso di questo<br/> " +
						"sito. Contatta l'amministratore per risolvere il<br/> " +
						"problema, oppure vai alla pagina di logout<br/> " +
						"e prova ad entrare con un altro utente:";
				content.add(new HTML(intro));
				content.add(logoutAnchor);
			}
			this.add(content);
			this.center();
			this.show();
		}
		
		//public void close() {
		//	this.hide();
		//	this.removeFromParent();
		//}
	}
}
